// code based on Tab X 0.5 enhanced version by Morac, modified by Hemiola SUN, later CPU & onemen

var nsIPrefServiceObj = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService);
var tabxBranch = "extensions.tabmix.";
var tabxPrefs = nsIPrefServiceObj.getBranch(tabxBranch);

var tabBarWidth = -1;
var tabBarHeight = -1;
var tabx;
var addtabx;
var tabxleft;
var tabscroll;
var hidebutton;
var max_width;
var min_width;
var flexTabs;
var gTabbarPosition;
var gSingleWindowMode;
var progress;
var tabBarSpace;
var unreadTab;
var optionsToolsMenu;
var alwaysNewTab;
var showIcons;
var showNewTabButton;
var noprogress;
var boldUnread;
var italicUnread;
var underlineUnread;
var useUnreadColor;
var useCurrentColor;
var useProgressColor;
var boldCurrent;
var italicCurrent;
var underlineCurrent;
var gFirefox2DefaultTheme;

function TMupdateSettings(start)
{
  if (!getBrowser() || tabxPrefs.prefHasUserValue("setDefault")) return;

  var i;
  tabx =             TMP_getBoolPref(tabxBranch, "tabXMode.enable",  true);
  addtabx =          TMP_getIntPref (tabxBranch, "tabXMode",         0);
  tabxleft =         TMP_getBoolPref(tabxBranch, "tabXLeft",         false);
  tabscroll =        TMP_getIntPref (tabxBranch, "tabBarMode",       2);
  hidebutton =       TMP_getBoolPref(tabxBranch, "hideTabBarButton", true);
  max_width  =       TMP_getIntPref (tabxBranch, "maxWidth",         250);
  min_width  =       TMP_getIntPref (tabxBranch, "minWidth",         30);
  flexTabs =         TMP_getBoolPref(tabxBranch, "flexTabs",         false);
  progress =         TMP_getBoolPref(tabxBranch, "progressMeter",    true);
  tabBarSpace =      TMP_getBoolPref(tabxBranch, "tabBarSpace",      false);
  unreadTab =        TMP_getBoolPref(tabxBranch, "unreadTab",        false);
  currentTab =       TMP_getBoolPref(tabxBranch, "currentTab",       false);
  noprogress =       TMP_getBoolPref(tabxBranch, "noprogress",       false);
  optionsToolsMenu = TMP_getBoolPref(tabxBranch, "optionsToolMenu",  true);
  alwaysNewTab =     TMP_getIntPref (tabxBranch, "speLink",          0);
  showIcons =        TMP_getBoolPref(tabxBranch, "extraIcons",       true);
  showNewTabButton = TMP_getBoolPref(tabxBranch, "newTabButton",     true);
  boldUnread =       TMP_getBoolPref(tabxBranch, "boldUnread",       true);
  italicUnread =     TMP_getBoolPref(tabxBranch, "italicUnread",     true);
  underlineUnread =  TMP_getBoolPref(tabxBranch, "underlineUnread",  true);
  boldCurrent =      TMP_getBoolPref(tabxBranch, "boldCurrent",      true);
  italicCurrent =    TMP_getBoolPref(tabxBranch, "italicCurrent",    true);
  underlineCurrent = TMP_getBoolPref(tabxBranch, "underlineCurrent", true);
  useCurrentColor =  TMP_getBoolPref(tabxBranch, "useCurrentColor",  true);
  useUnreadColor =   TMP_getBoolPref(tabxBranch, "useUnreadColor",   true);
  useProgressColor = TMP_getBoolPref(tabxBranch, "useProgressColor", false);

  var allTabs = getBrowser().mTabContainer.childNodes;
  var tabBar = getBrowser().mTabContainer;
  var tabBox = getBrowser().mTabBox;

  var currentVisible = tabBar.isTabVisible(getBrowser().mCurrentTab._tPos);

  var tabbarclosespacer = document.getElementById("tabbar-close-spacer");
  var tabbarclosebutton = document.getElementById("tabbar-close-button");
  var tabbarscrollbox = document.getElementById("tabs-scroll-up-down-box");
  var newbuttonbox = document.getElementById("tabs-newbutton-box");
  var tabhbox = document.getElementById("scroll-tabs-frame");
  var globalTabBox = document.getElementById("box-toggle-vertical");

  if (gTabbarPosition == 2) {
    tabBox.orient = "horizontal";
    globalTabBox.orient = "vertical";
    newbuttonbox.orient = "horizontal";
    tabhbox.orient = "vertical";
    gBrowser.mSplitter.style.display = "block";

    tabBox.setAttribute("dir","ltr");
    tabbarclosespacer.setAttribute("flex", "0");
    tabbarclosebutton.setAttribute("ordinal", "1");
    tabbarscrollbox.setAttribute("ordinal", "2");
    newbuttonbox.setAttribute("dir", "normal");

  } else if (gTabbarPosition == 1){
    tabBox.orient = "vertical";    
    globalTabBox.orient = "horizontal";
    newbuttonbox.orient = "vertical";
    tabhbox.orient = "horizontal";
    gBrowser.mSplitter.style.display = "none";

    tabBox.setAttribute("dir","rtl");
    tabbarclosespacer.setAttribute("flex", "1");
    tabbarclosebutton.setAttribute("ordinal", "2");
    tabbarscrollbox.setAttribute("ordinal", "1");
    newbuttonbox.setAttribute("dir", "reverse");

  } else {
    tabBox.orient = "vertical";    
    globalTabBox.orient = "horizontal";
    newbuttonbox.orient = "vertical";
    tabhbox.orient = "horizontal";
    gBrowser.mSplitter.style.display = "none";

    tabBox.setAttribute("dir","ltr");
    tabbarclosespacer.setAttribute("flex", "0");
    tabbarclosebutton.setAttribute("ordinal", "1");
    tabbarscrollbox.setAttribute("ordinal", "2");
    newbuttonbox.setAttribute("dir", "normal");
  }

  //workaround overflow bug
  tabhbox.className = '';
  window.setTimeout(function() { tabhbox.className = 'tabs-frame'; }, 0 );


  switch ( tabscroll ) {
    case 0:
      tabBar.setAttribute("flowing", "singlebar");
      break;
    case 1:
      if (tabBar.getAttribute("flowing") != "scrollbutton")
        tabBar.setAttribute("flowing", "scrollbutton");
      break;
    case 2:
      if (tabBar.getAttribute("flowing") != "multibar") {
         tabBar.setAttribute("flowing", "multibar");
         tabBar.collapsedTabs = 0;
      }
      var arrowBox = document.getElementById("tabs-scroll-up-down-box");
      if (tabBar.maxRow == 2 && !hidebutton)
         arrowBox.setAttribute("orient", "horizontal");
      else
         arrowBox.setAttribute("orient", "vertical");
      break;
  }

  if (!flexTabs)
    tabBar.collapsedTabs = 0;

  for (i = 0; i < allTabs.length; i++) {
    var aTab = allTabs[i];

    if (gTabbarPosition == 2) {
      if (aTab.hasAttribute("maxwidth")) aTab.removeAttribute("maxwidth");
      if (aTab.hasAttribute("minwidth")) aTab.removeAttribute("minwidth");
    } else {
      aTab.maxWidth = max_width;
      aTab.minWidth = min_width;
    }
    if (flexTabs && min_width != max_width) {
      if (aTab.hasAttribute("width")) aTab.removeAttribute("width");
      if (aTab.hasAttribute("flex")) aTab.removeAttribute("flex");
    } else {
      aTab.setAttribute("width", "0");
      if (gTabbarPosition != 2) {
        aTab.setAttribute("flex", "100");
      } else {
        if (aTab.hasAttribute("flex")) aTab.removeAttribute("flex");
      }
    }
    if ( alwaysNewTab == 1 )
      aTab.setAttribute("locked", "true");
    else if ( tabBar.getAttribute("lockAllTab") == "true" )
      aTab.removeAttribute("locked");

    SessionManager.updateTabProp(aTab);

    var tabxOptions = ["no-button","always","showhover","current","current_hover","always"];
    if (tabx)
    aTab.setAttribute("tabx", tabxOptions[addtabx]);
    else aTab.removeAttribute("tabx");

    if (tabxleft) aTab.setAttribute("tabxleft", "on");
    else aTab.removeAttribute("tabxleft");
  }

  tabBar.setAttribute("closebutton", !hidebutton);
  tabBar.setAttribute("progressMeter", progress);
  tabBar.setAttribute("tabBarSpace", tabBarSpace);
  tabBar.setAttribute("unreadTab", unreadTab);
  tabBar.setAttribute("extraIcons", showIcons );
  tabBar.setAttribute("lockAllTab", alwaysNewTab == 1 );
  tabBar.setAttribute("newTabButton", showNewTabButton );
  tabBar.setAttribute("boldUnread", boldUnread);
  tabBar.setAttribute("italicUnread", italicUnread);
  tabBar.setAttribute("underlineUnread", underlineUnread);
  tabBar.setAttribute("boldCurrent", boldCurrent);
  tabBar.setAttribute("italicCurrent", italicCurrent);
  tabBar.setAttribute("underlineCurrent", underlineCurrent);
  tabBar.setAttribute("currentTab", currentTab);
  tabBar.setAttribute("useCurrentColor", useCurrentColor);
  tabBar.setAttribute("useUnreadColor", useUnreadColor);
  tabBar.setAttribute("useProgressColor", useProgressColor);
  tabBar.setAttribute("tabbarOrientation", (gTabbarPosition == 2)? 'vertical':'horizontal');
  document.getElementById("statusbar-progresspanel").setAttribute("hidden", noprogress && progress);

  var tabhbox = document.getElementById("scroll-tabs-frame");
  if (tabhbox.style.maxHeight != "none" && !gBrowser.mStrip.collapsed && tabBar.childNodes[0].collapsed) {
    var currentMaxRow = tabhbox.style.maxHeight.replace("px", "") / getRowHeight();
    var rowDiff = tabBar.maxRow - currentMaxRow;
    while (tabBar.childNodes[0].collapsed && rowDiff > 0) {
      tabBar.rowScroll(-1);
      rowDiff--;
    }
  }

  if (start && "isLoadHomePage" in window) {
    window.setTimeout(tabBarScrollStatus, 0);
    delete window.isLoadHomePage;
  }
  else
    tabBarScrollStatus();

  tabBar.canScrollTabsLeft = tabBar.childNodes[0].collapsed;
  window.setTimeout( function() {
                         if (currentVisible)
                           tabBar.ensureTabIsVisible( getBrowser().mCurrentTab._tPos );
                           tabBar.canScrollTabsRight = !tabBar.rightEnd;
                           checkBeforeAndAfter();
                       }, 50 );

  if ( tabBarWidth == -1 ) // initialize the value of "tabBarWidth"
    window.setTimeout( function () {
                        tabBarWidth = gBrowser.mTabContainer.boxObject.width;
                      }, 100 );

  if ( tabBarHeight == -1 ) // initialize the value of "tabBarHeight"
    window.setTimeout( function () {
                        tabBarHeight = gBrowser.mTabContainer.boxObject.height;
                      }, 100 );

  // if the current Browser has SafeBrowsing problem and message is showing we need to
  // repaint the "safebrowsing-dim-area-canvas"
  window.setTimeout(adjustSafebrowsingDimArea, 0);

  // set some items
  document.getElementById("tabmix-menu").hidden = !optionsToolsMenu;

  var undocloseButton = document.getElementById("btn_undoclose");
  if (undocloseButton) closedTabBtnType(undocloseButton);

  TMP_LastTab.ReadPreferences();
  SessionManager.updateSettings(); // this update all open windows, if we fix here we need to change in SessionManager
}

// make btn_undoclose single-functionality or dual-functionality
function closedTabBtnType(undocloseButton)
{
   var menuOnly = TMP_getBoolPref(tabxBranch, "undoCloseButton.menuonly", false);

   if (!menuOnly)
      undocloseButton.removeAttribute("orient");
   else if (!undocloseButton.hasAttribute("orient"))
      undocloseButton.setAttribute("orient", "vertical");

   var buttonType = menuOnly ? "menu" : "menu-button";
   if (undocloseButton.getAttribute("type") != buttonType)
      undocloseButton.setAttribute("type", buttonType);
}

//overlay BrowserToolboxCustomizeDone
function TMP_BrowserToolboxCustomizeDone()
{
   var undocloseButton = document.getElementById("btn_undoclose");
   if (undocloseButton) {
      closedTabBtnType(undocloseButton);
      undocloseButton.setAttribute("disabled",gBrowser.closedTabs.length < 1);
   }
   var managerButten = document.getElementById("btn_sessionmanager");
   if (managerButten) {
      managerButten.setAttribute("disabled", !SessionManager.enableManager);
      var hiddenPref = document.getElementById("btn_closedwindows") ? true : false;
      document.getElementById("tm-sm-closedwindows1").hidden = hiddenPref;
   }
   fixTabmixButtons();
}

// fix Tabmix toolbarbutton in in FF 2.0 + theme
//(check to see if they change this)
function fixTabmixButtons()
{
   function setAttrib(id, attrib) {
      var button = document.getElementById(id);
      if (button && (!button.hasAttribute(attrib) || !button.getAttribute(attrib)))
         button.setAttribute(attrib,true);
   }

   var buttons = ["tabslist","closedwindows","undoclose","sessionmanager"];
   if (gIsFirefox2)
      Array.forEach(buttons, function(id) {setAttrib("btn_"+id, "firefox2");});
}

function TMP_SSTabRestoring(event){
  var aTab = event.target;
  if (aTab.hasAttribute("_locked")) {
    if (aTab.getAttribute("_locked") == "true")
      aTab.setAttribute("locked", "true");
    else
      aTab.removeAttribute("locked");
  }

  // this function ren befor tab load, so onTabReloaded will run at onStateChange get STATE_STOP
  var reloadData = aTab.getAttribute("reload-data");
  if (reloadData) {
    reloadData = reloadData.split(" ");
    gBrowser.setupAutoReload(aTab);
    aTab.autoReloadEnabled = true;
    aTab.autoReloadURI = reloadData[0];
    aTab.autoReloadTime = reloadData[1];
  }
}

// Function to catch when a new window is created and update icons if needed
//
function tabxOnLoad(event)
{
  var tabBar = getBrowser().mTabContainer;
  if (gIsFirefox2) {
    tabBar.setAttribute("firefox2", "true");

    if (/^Mac/.test(navigator.platform))
      tabBar.setAttribute("firefox2Mac", "true");
    else
      tabBar.setAttribute("firefox2notMac", "true");

    var skin = gPref.getCharPref("general.skins.selectedSkin");
    if (skin=="classic/1.0") {
      gFirefox2DefaultTheme = true;
      if (/^Mac/.test(navigator.platform))
        tabBar.setAttribute("firefox2MacDefaultTheme", "true");
      else
        tabBar.setAttribute("firefox2DefaultTheme", "true");
    }
  }

  // add event for update tab when restoring from nsSessionStore
  tabBar.addEventListener("SSTabRestoring", TMP_SSTabRestoring, true);

  // add event for creating a new tab
  tabBar.addEventListener("DOMNodeInserted", tabxTabAdded, true);

  // call tabxTabClosed from gBrowser.removeTab (eval) untile we will use "TabClose" event
  // tabBar.addEventListener("DOMNodeRemoved", tabxTabClosed, true);

  // don't show close tab button if there is only one blank tab or we keep last tab
  adjustCloseButtons(1);

  // add event for mouse scrolling on tab bar, necessary for linux
  tabBar.addEventListener("DOMMouseScroll", TMtabBarScroll, false);
  if (window.navigator.platform.search("Linux") != -1)
    document.getElementById("navigator-toolbox").addEventListener("DOMMouseScroll", TMtabBarScroll, false);

  if (gSingleWindowMode)
    tabxPrefObserver.setSingleWindowUI();

  tabxPrefObserver.setMenuIcons();
  tabxPrefObserver.toggleKey("key_tm_slideShow", "extensions.tabmix.disableF8Key");
  tabxPrefObserver.toggleKey("key_tm_toggleFLST", "extensions.tabmix.disableF9Key");
  tabxPrefObserver.setNewColorCode("currentTab", "extensions.tabmix.currentColor", "#000000");
  tabxPrefObserver.setNewColorCode("unreadTab", "extensions.tabmix.unreadColor", "#CC0000");
  tabxPrefObserver.setNewColorCode("progress", "extensions.tabmix.progressColor", "#AAAAFF");
  tabxPrefObserver.tabCloseButton();
  tabxPrefObserver.maxTabsUndo();

  // disable/enable tabmix buttons at startup
  var managerButten = document.getElementById("btn_sessionmanager");
  if (managerButten) {
    var hiddenPref = document.getElementById("btn_closedwindows") ? true : false;
    document.getElementById("tm-sm-closedwindows1").hidden = hiddenPref;
  }
  // fix Tabmix toolbarbutton in in FF 2.0 + theme
  fixTabmixButtons();

  gTabbarPosition = TMP_getIntPref (tabxBranch, "tabBarPosition", 0);
  // update icons if needed
  TMupdateSettings(true); // xxx we need diff function that call one on new window(s) and one for pref changed
}

function tabxOnClose()
{
  var tabBar = getBrowser().mTabContainer;
  tabBar.removeEventListener("SSTabRestoring", TMP_SSTabRestoring, true);
  tabBar.removeEventListener("DOMNodeInserted", tabxTabAdded, true);
  tabBar.removeEventListener("DOMMouseScroll", TMtabBarScroll, false);
  if (window.navigator.platform.search("Linux") != -1)
    document.getElementById("navigator-toolbox").removeEventListener("DOMMouseScroll", TMtabBarScroll, false);
}

function tabxTabClosed(aTab)
{
  var tabs = getBrowser().mTabContainer.childNodes;
  var tabBar = getBrowser().mTabContainer;
  var firstTab = tabs[0];

  // don't show close tab button if there is only one blank tab or we keep last tab
  adjustCloseButtons(2, aTab);

  if ( tabscroll != 2 ) {
    tabBar.collapsedTabs--;
    tabBar.canScrollTabsLeft = firstTab.collapsed;
    window.setTimeout( function() {
                         tabBar.canScrollTabsRight = !tabBar.rightEnd;
                         setTabBarHeight();
                       }, 50 );
  }
  else {
    window.setTimeout( function() {
       if ( tabBar.getAttribute("multibar") == "scrollbar" && firstTab.collapsed ) {
          if ((tabBar.lastChild.baseY + tabBar.lastChild.boxObject.height/2) < (tabBar.boxObject.y + tabBar.boxObject.height)) {
                tabBar.rowScroll(-1);
          }
       }
       tabBarScrollStatus();
       checkBeforeAndAfter();
    }, 0);
  }

  // if the current Browser has SafeBrowsing problem and message is showing we need to
  // repaint the "safebrowsing-dim-area-canvas"
  window.setTimeout(adjustSafebrowsingDimArea, 0);
}

// Function to catch when new tabs are created and update tab icons if needed
// In addition clicks and doubleclick events are trapped.
//
function tabxTabAdded(event)
{
  if (event.target.localName != "tab" || event.target.hasAttribute("tabmoved"))
    return;

   var aTab = event.target;

   // XXX splice, appendChild, insertBefore from gBrowser.moveTabTo
   // trigger tabxTabClosed and tabxTabAdded
   if (aTab._added) {
      delete aTab._added;
      return;
   }

   aTab._added = true;

   // don't show close tab button if there is only one blank tab or we keep last tab
   adjustCloseButtons(1);

   var tabxOptions = ["no-button","always","showhover","current","current_hover","always"];
   if (tabx) aTab.setAttribute("tabx", tabxOptions[addtabx]);
   else aTab.removeAttribute("tabx");

   if (tabxleft) aTab.setAttribute("tabxleft", "on");
   else aTab.removeAttribute("tabxleft");

   if (gTabbarPosition == 2) {
     if (aTab.hasAttribute("maxwidth")) aTab.removeAttribute("maxwidth");
     if (aTab.hasAttribute("minwidth")) aTab.removeAttribute("minwidth");
   } else {
     aTab.maxWidth = max_width;
     aTab.minWidth = min_width;
   }
   if (flexTabs && min_width != max_width) {
     if (aTab.hasAttribute("width")) aTab.removeAttribute("width");
     if (aTab.hasAttribute("flex")) aTab.removeAttribute("flex");
   } else {
     aTab.setAttribute("width", "0");
     if (gTabbarPosition != 2) {
       aTab.setAttribute("flex", "100");
     } else {
       if (aTab.hasAttribute("flex")) aTab.removeAttribute("flex");
     }
   }
   if ( alwaysNewTab == 1 )
     aTab.setAttribute("locked", "true");
     // XXX SessionManager.updateTabProp(aTab); // tab is blank at this stage

   tabBarScrollStatus();

   // if the current Browser has SafeBrowsing problem and message is showing we need to
   // repaint the "safebrowsing-dim-area-canvas"
   adjustSafebrowsingDimArea();
}

function tabBarScrollStatus ()
{
  var allTabs = getBrowser().mTabContainer.childNodes;
  var tabBar = getBrowser().mTabContainer;

  tabBar.canScrollTabsLeft = allTabs[0].collapsed;

  if ( tabscroll == 2 ) {
    tabBar.setAttribute("multibar", "true");
    setMultibarAttribute();
  }
  else
    tabBar.removeAttribute("multibar");

  setTabBarHeight();

  tabBar.canScrollTabsRight = !tabBar.rightEnd;
}

function setMultibarAttribute ()
{
  var tabBar = getBrowser().mTabContainer;
  if (tabBar.collapsedTabs > 0)
     tabBar.setAttribute("multibar", "scrollbar");
  else if (gBrowser.mStrip.collapsed || inSameRow(tabBar.firstChild, tabBar.lastChild))
     tabBar.removeAttribute("multibar");
  else {
     var tabhbox = document.getElementById("scroll-tabs-frame");
     var maxY = tabhbox.boxObject.y + getRowHeight() * tabBar.maxRow;
     // if the top of the last tab is on or below the max line then enter scrollbar
     var lastTabY = tabBar.lastChild.boxObject.y;
     if (lastTabY >= maxY)
        tabBar.setAttribute("multibar", "scrollbar");
     else if (tabBar.getAttribute("multibar") != "true")
        tabBar.setAttribute("multibar", "true");
  }
}

function checkBeforeAndAfter()
{
  var tab = getBrowser().mTabContainer.selectedItem;
  var prev = tab.previousSibling, next = tab.nextSibling;
  if (prev) {
    if ( !inSameRow(prev, tab) ) prev.removeAttribute("beforeselected");
    else prev.setAttribute("beforeselected", "true");
  }
  if (next) {
    if ( !inSameRow(next, tab) ) next.removeAttribute("afterselected");
    else next.setAttribute("afterselected", "true");
  }
}

function getRowHeight ()
{
  var tabBar = getBrowser().mTabContainer;
  var tabs = getBrowser().mTabContainer.childNodes;

  var i, j;
  i = j = tabBar.collapsedTabs;
  if ( tabs[j] && tabs[j].getAttribute("selected") == "true" )
    j++;
  while ( inSameRow( tabs.item(i), tabs.item(j) ) )
    i++;

  if ( !tabs[i] ) // only one row
    if ( tabs[j] )
      return tabs[j].baseY - tabs[j].boxObject.y;
    else
      return tabs[0].baseY - tabs[0].boxObject.y;

  if ( tabs[i].getAttribute("selected") == "true" )
    i++;
  if ( !tabs[i] )
    return tabs[i-1].baseY - tabs[i-1].boxObject.y;
  return tabs[i].baseY - tabs[j].baseY;
}

function setTabBarHeight () {
  var tabBar = getBrowser().mTabContainer;
  var tabhbox = document.getElementById("scroll-tabs-frame");

  if ( tabBar.getAttribute("flowing") == "multibar" && tabBar.getAttribute("multibar") == "scrollbar" ) {
    tabhbox.style.maxHeight = tabhbox.style.height = getRowHeight() * tabBar.maxRow + "px";
    document.getElementById("tabmix-tabs-closebutton-box").pack = "start";
  }
  else {
    if ( tabBar.getAttribute("flowing") == "multibar" && tabBar.getAttribute("multibar") == "true")
      document.getElementById("tabmix-tabs-closebutton-box").pack = "start";
    else
      document.getElementById("tabmix-tabs-closebutton-box").pack = "center";
    if (gTabbarPosition != 2) {
      tabhbox.style.maxHeight = "none";
      tabhbox.style.height = "auto";
    }
  }
}

function inSameRow (tab1, tab2)
{
  if ( !tab1 || !tab2 )
    return false;
  if ( !tabscroll || tabscroll != 2 )
    return true;

  var top1 = tab1.boxObject.y, top2 = tab2.boxObject.y;
  var base1 = tab1.baseY, base2 = tab2.baseY;
  var topH = Math.min(top1, top2), topL = Math.max(top1, top2);
  var baseH = Math.min(base1, base2), baseL = Math.max(base1, base2);

  if ( topH == topL || baseH == baseL )
    return true;

  return ( baseH > (top1+base1)/2 && baseH > (top2+base2)/2 && topL < (top1+base1)/2 && topL < (top2+base2)/2 ) ?
    true : false;
}

function tabBarWidthChange () {
  var tabBar = getBrowser().mTabContainer;
  var tabhbox = document.getElementById("scroll-tabs-frame");
  var tabs = getBrowser().mTabContainer.childNodes;

  if (addtabx == 5 && !flexTabs)
    adjustCloseButtons(1);

  if (gTabbarPosition == 2) {
    if ( tabBarHeight == tabBar.boxObject.height )
      return;
    var oldCollapsed = tabBar.collapsedTabs;
    var i = 0;
    if ( tabscroll != 2 && tabBarHeight < tabBar.boxObject.height ) {
      while ( tabs[ oldCollapsed + i ] &&
              tabs[ oldCollapsed + i ].boxObject.y + tabs[ oldCollapsed + i ].boxObject.height <
              tabhbox.boxObject.y + tabhbox.boxObject.height )
        i++;
      tabBar.collapsedTabs = 0;
      tabBar.ensureTabIsVisible( oldCollapsed + i - 1 );
      tabBarScrollStatus();
    }
    else
      tabBarScrollStatus();

    tabBarHeight = tabBar.boxObject.height;

  } else {
    if ( tabBarWidth == tabBar.boxObject.width )
      return;
    var oldCollapsed = tabBar.collapsedTabs;
    var i = 0;
    if ( tabscroll != 2 && tabBarWidth < tabBar.boxObject.width ) {
      while ( tabs[ oldCollapsed + i ] &&
              tabs[ oldCollapsed + i ].boxObject.x + tabs[ oldCollapsed + i ].boxObject.width <
              tabhbox.boxObject.x + tabhbox.boxObject.width )
        i++;
      tabBar.collapsedTabs = 0;
      tabBar.ensureTabIsVisible( oldCollapsed + i - 1 );
      tabBarScrollStatus();
    }
    else if ( tabscroll == 2 ) {
      tabBar.collapsedTabs = 0;
      tabBarScrollStatus();
      tabBar.ensureTabIsVisible( tabs.length - 1);
      tabBar.ensureTabIsVisible( oldCollapsed );
      checkBeforeAndAfter();
    }
    else
      tabBarScrollStatus();
  
    tabBarWidth = tabBar.boxObject.width;
  }
}

// Function to catch changes to Tab Mix preferences and update existing windows and tabs
//
function tabxPrefObserver() {
  var pref = "setDefault"
  if (tabxPrefs.prefHasUserValue(pref)) tabxPrefs.clearUserPref(pref)
  pref = "PrefObserver.error";
  if (tabxPrefs.prefHasUserValue(pref)) tabxPrefs.clearUserPref(pref)
  try {
    var prefSvc = nsIPrefServiceObj.getBranch(null);
    this.tabxBranch = tabxBranch;
    if (!Components.interfaces.nsIPrefBranch2)
      this.pbi = prefSvc.QueryInterface(Components.interfaces.nsIPrefBranchInternal); // for 1.0.7
    else
      this.pbi = prefSvc.QueryInterface(Components.interfaces.nsIPrefBranch2);

    // add Observer
    for (var i = 0; i < this.OBSERVING.length; ++i)
      this.pbi.addObserver(this.OBSERVING[i], this, true);
  }
  catch(e) {
    tmLog("prefs-Observer failed to attach:" + "\n" + e);
    tabxPrefs.setBoolPref(pref, true);
  }
}

tabxPrefObserver.prototype = {
  tabxBranch: null,
  // nsISupports interface implementation -- for weak-reference by pref-observer service
  QueryInterface: function(iid) {
    if (!iid.equals(Components.interfaces.nsISupports)
        && !iid.equals(Components.interfaces.nsISupportsWeakReference)
        && !iid.equals(Components.interfaces.nsIObserver)) {
      dump("Tab Tree Mix pref-observer factory object: QI unknown interface: " + iid + "\n");
      throw Components.results.NS_ERROR_NO_INTERFACE;
    }
    return this;
  },

  OBSERVING: ["extensions.tabmix.",
              "browser.tabs.tabClipWidth", "browser.sessionstore.max_tabs_undo",
              "browser.sessionstore.enabled", "browser.link.open_external",
              "browser.link.open_newwindow.restriction", "browser.link.open_newwindow"],

  // removes the observer-object from service -- called when the window is no longer open
  removeObserver: function() {
    for (var i = 0; i < this.OBSERVING.length; ++i)
      this.pbi.removeObserver(this.OBSERVING[i], this);

    this.pbi = null;
  },

  /* Observer-function */
  /* subject: [wrapped nsISupports :: nsIPrefBranch], nsIPrefBranch Internal
     topic: "changed"*/
  observe: function TMP_pref_observer(subject, topic, prefName) {
    // if we don't have a valid window (closed)
    if ( !(typeof(document) == 'object' && document) ) {
      this.removeObserver(); // remove the observer..
      return;  // ..and don't continue
    }

    switch (prefName) {
      case "extensions.tabmix.warnAboutClosingTabs.timeout":
      case "extensions.tabmix.sessions.crashed":
      case "extensions.tabmix.disableIncompatible":

      case "extensions.tabmix.selected_tab":
      case "extensions.tabmix.selected_sub_tab1":
      case "extensions.tabmix.selected_sub_tab2":
      case "extensions.tabmix.selected_sub_tab3":
      case "extensions.tabmix.selected_sub_tab4":
      case "extensions.tabmix.selected_sub_tab5":
      case "extensions.tabmix.selected_sub_tab6":

      case "extensions.tabmix.reload_time":
      case "extensions.tabmix.custom_reload_time":
      case "extensions.tabmix.resume_session_once":
        break;
      case "extensions.tabmix.focusTab":
        if (gIsFirefox2)
          gPref.setBoolPref("browser.tabs.selectOwnerOnClose", gPref.getIntPref(prefName) == 2);
        break;
      case "extensions.tabmix.disableF9Key":
        this.toggleKey("key_tm_toggleFLST", prefName);
        break;
      case "extensions.tabmix.disableF8Key":
        this.toggleKey("key_tm_slideShow", prefName);
        break;
      case "extensions.tabmix.hideIcons":
        this.setMenuIcons();
        break;
      case "extensions.tabmix.currentColorCode":
        this.setColor("currentTab", prefName, "#009900");
        break;
      case "extensions.tabmix.unreadColorCode":
        this.setColor("unreadTab", prefName, "#FF0000");
        break;
      case "extensions.tabmix.progressColorCode":
        this.setColor("progress", prefName, "#AAAAFF");
        break;
      case "extensions.tabmix.flexTabs":
      case "extensions.tabmix.tabXMode":
        TMupdateSettings(false);
      case "extensions.tabmix.keepLastTab":
      case "browser.tabs.tabClipWidth":
        // don't show close tab button if there is only one blank tab or we keep last tab
        // or if tab width is smaller then pref and not in flexTabs mode.
        adjustCloseButtons(1);
        break;
      case "extensions.tabmix.tabBarPosition":
         gTabbarPosition = TMP_getIntPref (tabxBranch, "tabBarPosition", 0);
         adjustSafebrowsingDimArea();
        break;
      case "extensions.tabmix.useGreyCloseButton":
        this.tabCloseButton();
        break;
      case "browser.sessionstore.max_tabs_undo":
        try {
          var cache = gPref.getIntPref(prefName);
        } catch (e) { cache = 10; }
        tabxPrefs.setIntPref("undoCloseCache", cache);
        break;
      case "extensions.tabmix.undoClose":
      case "extensions.tabmix.undoCloseCache":
        this.maxTabsUndo();
        SessionManager.updateSettings();
        break;
      case "browser.sessionstore.enabled":
        TMP_SessionStore.setService(1, false);
        // initialize nsISessionStore if necessary
        if (gIsFirefox2 && TMP_getBoolPref("", prefName, true) && !window.__SSi) {
          TMP_SessionStore.init(true);
        }
        break;
      case "extensions.tabmix.sessions.manager":
      case "extensions.tabmix.sessions.crashRecovery":
        TMP_SessionStore.setService(2, false);
        SessionManager.updateSettings();
        break;
      case "browser.link.open_external":
      case "browser.link.open_newwindow.restriction":
      case "browser.link.open_newwindow":
        this.setLink_openPrefs();
        break;
      case "extensions.tabmix.singleWindow":
        this.setSingleWindowUI();
        break;
      default:
        TMupdateSettings(false);
    }

  },

  tabCloseButton: function() {
    var useNewCloseIcon;
    try {
      useNewCloseIcon = tabxPrefs.getBoolPref("useGreyCloseButton");
    }
    catch(er) { useNewCloseIcon = true; }
    if (useNewCloseIcon && !(/^Mac/.test(navigator.platform)) )
      getBrowser().mTabContainer.removeAttribute("dontUseNewCloseIcon");
    else
      getBrowser().mTabContainer.setAttribute("dontUseNewCloseIcon", "true");
  },

  toggleKey: function(keiID, prefName) {
    var key = document.getElementById(keiID);
    if (TMP_getBoolPref("", prefName, false)) {
      if (key.hasAttribute("oncommand"))
        key.removeAttribute("oncommand");
    } else
      key.setAttribute("oncommand", key.getAttribute("TM_oncommand"));
  },

  // in 0.3.0.605 we changed tab color from old pref to new pref
  // old pref "extensions.tabmix.currentColor" type integer
  // new pref "extensions.tabmix.currentColorCode" type string
  setNewColorCode: function(colorType, OldprefName, defaultPref) {
    var prefName = OldprefName + "Code";

    if (gPref.prefHasUserValue(OldprefName)) {
      var colorCodes = ["#CF1919", "#0E36EF", "#DDDF0D", "#3F8F3E", "#E066FF", "#86E7EF",
                         "#FFFFFF", "#7F7F7F", "#000000", "#EF952C", "#FF82AB", "#7F4C0F", "#AAAAFF"];
      var colorCode = colorCodes[gPref.getIntPref(OldprefName)];
      gPref.clearUserPref(OldprefName);
      if (gPref.getCharPref(prefName) != colorCode) {
         gPref.setCharPref(prefName , colorCode); // this trigger call to setColor for this prefName
         return;
      }
    }
    this.setColor(colorType, prefName, defaultPref);
  },

  colorRules: {},
  setColor: function(colorType, prefName, defaultPref) {
    var colorCode = TMP_getCharPref("", prefName, defaultPref);
    var colorRule, _style;

    switch (colorType) {
      case "currentTab":
         _style = "color";
        colorRule = 'tabs[currentTab=true][useCurrentColor=true] tab[selected="true"] .tab-text { color:' + colorCode + '}';
        break;
      case "unreadTab":
         _style = "color";
        colorRule = 'tabs[unreadTab=true][useUnreadColor=true] tab:not([selected]) .tab-text { color:' + colorCode + '}';
        break;
      case "progress":
         _style = "backgroundColor";
        colorRule = 'tabs[useProgressColor=true] tab .progress-bar { background-color:' + colorCode + '}';
        break;
    }

    var ss = document.styleSheets[0];

    if (this.colorRules[colorType])
      this.colorRules[colorType].style[_style] = colorCode;
    else
    {
      var index = ss.insertRule(colorRule, ss.cssRules.length);
      this.colorRules[colorType] = ss.cssRules[index];
    }
  },

  maxTabsUndo: function() {
    if (!gIsFirefox2)
      return;
    var max_tabs_undo = "browser.sessionstore.max_tabs_undo";
    if (tabxPrefs.getBoolPref("undoClose")) {
      var cache = tabxPrefs.getIntPref("undoCloseCache");
      if (cache != 10)
        gPref.setIntPref(max_tabs_undo, cache);
      else if (gPref.prefHasUserValue(max_tabs_undo))
        gPref.clearUserPref(max_tabs_undo);
    }
    else
      gPref.setIntPref(max_tabs_undo, 0);
  },

  setLink_openPrefs: function() {
    if (!gSingleWindowMode)
      return;

    function updateStatus(pref, testVal, test, newVal) {
      try {
        var prefValue = gPref.getIntPref(pref);
        test = test ? prefValue == testVal : prefValue != testVal
      }
      catch(e){ test = true; }

      if (test)
        gPref.setIntPref(pref, newVal);
    }

    updateStatus("browser.link.open_external", 2, true, 3);
    updateStatus("browser.link.open_newwindow.restriction", 0, false, 0);
    updateStatus("browser.link.open_newwindow", 2, true, 3);
  },

  // code for Single Window Mode...
  // disable the "Open New Window action
  //disable & hides some menuitem
  setSingleWindowUI: function() {
    gSingleWindowMode = TMP_getBoolPref(tabxBranch, "singleWindow", false);
    var newWindowButton = document.getElementById("new-window-button");
    if (newWindowButton)
      newWindowButton.setAttribute("disabled", gSingleWindowMode);

    var openLink = document.getElementById("context-openlink");
    if (openLink)
      openLink.setAttribute("disabled", gSingleWindowMode);

    var menuItem;
    var menuFile = document.getElementById("menu_FilePopup");
    if (menuFile) {
      menuItem = menuFile.getElementsByAttribute("command", "cmd_newNavigator")[0];
      if (menuItem)
        menuItem.setAttribute("hidden", gSingleWindowMode);
    }

    var frameMenu = document.getElementById("frame");
    if (frameMenu) {
      menuItem = frameMenu.getElementsByAttribute("oncommand", "gContextMenu.openFrame();")[0];
      if (menuItem)
        menuItem.setAttribute("hidden", gSingleWindowMode);
    }

    document.getElementById("tmOpenInNewWindow").hidden = gSingleWindowMode;
  },

  setMenuIcons: function() {
    function setClass(items, hideIcons) {
      if (hideIcons)
        for (var i = 0; i < items.length; ++i)
          items[i].removeAttribute("class");
      else
        for ( i = 0; i < items.length; ++i)
          items[i].setAttribute("class", items[i].getAttribute("tmp_iconic"));
    }
    var hideIcons = TMP_getBoolPref(tabxBranch, "hideIcons", false);
    var iconicItems = document.getElementsByAttribute("tmp_iconic", "*");
    setClass(iconicItems, hideIcons);

    iconicItems = document.getElementById("menuedit-tabContextMenu").getElementsByAttribute("tmp_iconic", "*");
    setClass(iconicItems, hideIcons);
  }

}

function TMtabBarScroll (event)
{
  var tabs = getBrowser().mTabContainer.childNodes;
  var tabBar = getBrowser().mTabContainer;

  for (var i = 0; i < tabs.length; i++)
    tabs[i].setAttribute("showbutton","off");

  var ScrollDirection = event.detail > 0 ? 1 : -1;
  if (gPref.getBoolPref("extensions.tabmix.reversedScroll"))
    ScrollDirection = -1 * ScrollDirection;

  var shouldMoveFocus = gPref.getBoolPref("extensions.tabmix.enableScrollSwitch");
  if (shouldMoveFocus)
    tabBar.advanceSelectedTab(ScrollDirection, true);
  else if ( gPref.getIntPref("extensions.tabmix.tabBarMode") != 2 )
    tabBar.collapsedTabs += ScrollDirection;
  else if ( gPref.getIntPref("extensions.tabmix.tabBarMode") == 2 )
    tabBar.rowScroll(ScrollDirection);
}

function adjustCloseButtons (aNumTabs, oldTab)
{
   // don't show close tab button if there is only one blank tab or we keep last tab
   var tabBar = getBrowser().mTabContainer;
   var tabs = tabBar.childNodes;

   var aTab = aNumTabs == 2 && tabs[0] == oldTab ? tabs[1] : tabs[0];
   if (tabs.length == aNumTabs &&
            (TMP_getBoolPref(tabxBranch, "keepLastTab", false) || getBrowser().isBlankTab(aTab)))
      tabBar.setAttribute("hidebutton", "true");
   else if (tabBar.hasAttribute("hidebutton"))
      tabBar.removeAttribute("hidebutton");

   // don't show close tab button if tab width is smaller then pref and not in flexTabs mode
   setTimeout( function(tabBar) {
      // make sure not to check collapsed tab for width
      var width = tabBar.lastChild.boxObject.width;
      // 0 width is an invalid value and indicates an item without display,
      // so ignore.
      var tabClipWidth = TMP_getIntPref("", "browser.tabs.tabClipWidth", 140);
      var attributeChanged = false;
      if (addtabx != 5 || flexTabs || width > tabClipWidth || width == 0) {
         if (tabBar.hasAttribute("tinywidth")) {
            tabBar.removeAttribute("tinywidth");
            attributeChanged = true;
         }
      }
      else if (!tabBar.hasAttribute("tinywidth")) {
         tabBar.setAttribute("tinywidth", "true");
         attributeChanged = true;
      }

      if (attributeChanged) {
         tabBarScrollStatus();
         checkBeforeAndAfter();
      }
   }, 0, tabBar);
}

// in Firefox 2.0 + with safebrowsing
// if the current Browser has problem and message is showing we need to
// repaint the "safebrowsing-dim-area-canvas" if we add or remove tabs and
// if we change tabbar position
function adjustSafebrowsingDimArea() {
   if (!gIsFirefox2)
      return;

   var sbC = safebrowsing.controller;
   if (sbC == null)
      return;

   var browser = sbC.tabWatcher_.getCurrentBrowser();
   if (sbC.browserView_.hasProblem(browser)) {
      var displayer = sbC.browserView_.getCurrentProblem_(browser).displayer_;
      if (displayer.messageShowing_) {
         displayer.hideMessage_();
         displayer.showMessage_();
      }
   }
}

function TMP_getBoolPref(branch, prefname, def )
{
  try {
    if (!gPref)
      gPref = getPref();
    return gPref.getBoolPref(branch+prefname);
  }
  catch(er) {
    gPref.setBoolPref(branch+prefname, def);
    return def;
  }
}

function TMP_getIntPref(branch, prefname, def )
{
  try {
    if (!gPref)
      gPref = getPref();
    return gPref.getIntPref(branch+prefname);
  }
  catch(er) {
    gPref.setIntPref(branch+prefname, def);
    return def;
  }
}

function TMP_getCharPref(branch, prefname, def )
{
  try {
    if (!gPref)
      gPref = getPref();
    return gPref.getCharPref(branch+prefname);
  }
  catch(er) {
    gPref.setCharPref(branch+prefname, def);
    return def;
  }
}

function getPref()
{
   return Components.classes["@mozilla.org/preferences-service;1"]
            .getService(Components.interfaces.nsIPrefBranch);
}

var TMP_ProgressListener = {
   init: function TMP_PL_init(progressListener) {
      var _this = "TMP_ProgressListener."
/*
// XXX this is not working in FF 1.0.x ???
      eval("progressListener.onProgressChange = " + progressListener.onProgressChange.toString()
            .replace(/}$/,
            'this.onStateChange(aWebProgress, aRequest);' +
            _this + 'setTabProgress(this.mTab, aMaxTotalProgress, aCurTotalProgress); \ $&'));
*/

      function addToTheEnd(fnName, newString) {
         var fnString = progressListener[fnName].toString();
         fnString = fnString.substr(0, fnString.length - 2) + newString;
         eval("progressListener." + fnName + " = " + fnString);
      }
      
      addToTheEnd('onProgressChange',
                  'this.onStateChange(aWebProgress, aRequest);' +
                  _this + 'setTabProgress(this.mTab, aMaxTotalProgress, aCurTotalProgress); \ }');

      // we need to be compatible with XHTML Ruby Support
      var fnName = "onStateChange";
      var ruby = "__rubysupport__" + fnName;
      if (ruby in progressListener)
         fnName = ruby;

      eval("progressListener." + fnName + " = " + progressListener[fnName].toString().replace(
            'this.mTab.setAttribute("busy", "true");',
            '$&' +  _this + "setTabWidth(this.mTab, this.mBrowser);"
         ).replace(
            'var location = aRequest.QueryInterface(nsIChannel).URI;',
            _this + 'setUnreadTab(this.mTab); \ $&'));

      addToTheEnd(fnName,
                  _this + 'setAutoReload(this.mTab, this.mBrowser, aStateFlags); \ }');

      // XXX how to do this with Regexp and replace ?
      var string = "if (this.mTabBrowser.mCurrentTab == this.mTab)";
      var split_fn = progressListener[fnName].toString().split(string);
      split_fn[1] += _this + 'updateSessionManager(this.mTab);'
      eval("progressListener." + fnName + " = " + split_fn.join(string));

      eval("progressListener.onLocationChange = " + progressListener.onLocationChange.toString().replace(
            'if (this.mBrowser.userTypedClear',
            _this + 'callAdjustCloseButtons(); \ $&'));

      if (gIsFirefox2)
         addToTheEnd('onLocationChange',
                     _this + 'fixBug355253(this.mBrowser); \ }');

      return progressListener;
   },

   setTabProgress: function TMP_PL_setTabProgress(aTab, aMaxTotalProgress, aCurTotalProgress) {
      if (aMaxTotalProgress < 1)
         return;
      var percentage = parseInt((aCurTotalProgress * 100) / aMaxTotalProgress);
      if (percentage > 0 && percentage < 100)
         aTab.setAttribute("tab-progress", percentage);
   },

   setTabWidth: function TMP_PL_setTabWidth(aTab, aBrowser) {
      if (flexTabs && max_width != min_width && !aTab.hasAttribute("width") &&
            aTab.label != gBrowser.mStringBundle.getString("tabs.untitled")) {
         var uri = aBrowser.currentURI;
         if (uri && uri.spec != aTab.label && uri.spec != "about:blank")
            aTab.setAttribute("width", aTab.boxObject.width);
      }
   },

   setUnreadTab: function TMP_PL_setUnreadTab(aTab) {
      aTab.removeAttribute("tab-progress");
      if (gPref.getBoolPref("extensions.tabmix.unreadTab") &&
            aTab.hasAttribute("selected") &&
            gPref.getBoolPref("extensions.tabmix.unreadTabreload") &&
            aTab.getAttribute("selected") == "false")
         aTab.removeAttribute("selected");
   },

   updateSessionManager: function TMP_PL_updateSessionManager(aTab) {
      if (aTab.label != gBrowser.mStringBundle.getString("tabs.loading"))
         SessionManager.tabLoaded(aTab);
   },

   setAutoReload: function TMP_PL_setAutoReload(aTab, aBrowser, aStateFlags) {
      const nsIWebProgressListener = Components.interfaces.nsIWebProgressListener;
      if ((aStateFlags & nsIWebProgressListener.STATE_IS_WINDOW) &&
            (aStateFlags & nsIWebProgressListener.STATE_STOP) &&
            aTab.autoReloadEnabled)
         gBrowser.onTabReloaded(aTab, aBrowser);
   },

   callAdjustCloseButtons: function TMP_PL_callAdjustCloseButtons() {
      if (gBrowser.mTabs.length == 1)
         adjustCloseButtons(1);
   },

// XXX temp fix to bug 355253
   // recently closed tabs doesn't saved closed tab if it have "about:blank" first in history.
   fixBug355253: function TMP_PL_fixBug355253(aBrowser) {
      var history = aBrowser.webNavigation.sessionHistory;
      if (history && history.count == 2 && history.index == 1 &&
            history.getEntryAtIndex(0, false).URI.spec == "about:blank") {
         aBrowser.observe(null, "browser:purge-session-history", null);
         var backCommand = document.getElementById("Browser:Back");
         if (backCommand)
            backCommand.setAttribute("disabled", "true");
      }
   }

}
